package com.example.data.jdbc.dao;

import com.querydsl.core.types.dsl.*;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * @author fanhang
 */
public class PredicateBuilder<T> {
    private final BooleanExpression result = Expressions.asBoolean(true).isTrue();

    private final PathBuilder<T> entityPath;

    public PredicateBuilder(Class<T> clazz, String name) {
        this.entityPath = new PathBuilder<>(clazz, name);
    }

    public void add(String operation, String key, Object value) {
        if (value instanceof Long val) {
            this.result.and(this.build(operation, key, val));
        }
        if (value instanceof Integer val) {
            this.result.and(this.build(operation, key, val));
        }
        if (value instanceof Double val) {
            this.result.and(this.build(operation, key, val));
        }
        if (value instanceof Float val) {
            this.result.and(this.build(operation, key, val));
        }
        if (value instanceof BigDecimal val) {
            this.result.and(this.build(operation, key, val));
        }
        if (value instanceof Short val) {
            this.result.and(this.build(operation, key, val));
        }
        if (value instanceof BigInteger val) {
            this.result.and(this.build(operation, key, val));
        }
        if (value instanceof String val) {
            this.result.and(this.build(operation, key, val));
        }
    }

    public BooleanExpression get() {
        return result;
    }

    private BooleanExpression build(String operation, String key, Long value) {
        NumberPath<Long> path = entityPath.getNumber(key, Long.class);
        return switch (operation) {
            case ":" -> path.eq(value);
            case ">" -> path.goe(value);
            case "<" -> path.loe(value);
            default -> null;
        };
    }

    private BooleanExpression build(String operation, String key, Integer value) {
        NumberPath<Integer> path = entityPath.getNumber(key, Integer.class);
        return switch (operation) {
            case ":" -> path.eq(value);
            case ">" -> path.goe(value);
            case "<" -> path.loe(value);
            default -> null;
        };
    }

    private BooleanExpression build(String operation, String key, Double value) {
        NumberPath<Double> path = entityPath.getNumber(key, Double.class);
        return switch (operation) {
            case ":" -> path.eq(value);
            case ">" -> path.goe(value);
            case "<" -> path.loe(value);
            default -> null;
        };
    }

    private BooleanExpression build(String operation, String key, Float value) {
        NumberPath<Float> path = entityPath.getNumber(key, Float.class);
        return switch (operation) {
            case ":" -> path.eq(value);
            case ">" -> path.goe(value);
            case "<" -> path.loe(value);
            default -> null;
        };
    }

    private BooleanExpression build(String operation, String key, BigDecimal value) {
        NumberPath<BigDecimal> path = entityPath.getNumber(key, BigDecimal.class);
        return switch (operation) {
            case ":" -> path.eq(value);
            case ">" -> path.goe(value);
            case "<" -> path.loe(value);
            default -> null;
        };
    }

    private BooleanExpression build(String operation, String key, Short value) {
        NumberPath<Short> path = entityPath.getNumber(key, Short.class);
        return switch (operation) {
            case ":" -> path.eq(value);
            case ">" -> path.goe(value);
            case "<" -> path.loe(value);
            default -> null;
        };
    }

    private BooleanExpression build(String operation, String key, BigInteger value) {
        NumberPath<BigInteger> path = entityPath.getNumber(key, BigInteger.class);
        return switch (operation) {
            case ":" -> path.eq(value);
            case ">" -> path.goe(value);
            case "<" -> path.loe(value);
            default -> null;
        };
    }

    private BooleanExpression build(String operation, String key, String value) {
        StringPath path = entityPath.getString(key);
        if (":".equalsIgnoreCase(operation)) {
            return path.containsIgnoreCase(value);
        }
        return null;
    }
}
